package commonAdmin.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import commonAdmin.domain.Page;
import commonAdmin.domain.WebPageSearchCondition;
import commonAdmin.service.BaseService;
import commonAdmin.sql.support.ModelTableInfo;
import commonAdmin.util.ObjectUtil;

/**
 * 封装controller CRUD操作
 * @author Jack
 * 2016年1月30日下午6:21:48
 */
public abstract class CRUDController<T, ID> {

	private static final Logger log = LoggerFactory.getLogger(CRUDController.class);

	/** 表单页面 **/
	protected  String form_view_page;
	/** 视图页面 **/
	protected  String object_view_page;
	/** 列表页面 **/
	protected  String list_view_page;

	/** Controller的访问url **/
	protected String controllerRequestMappingValue;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public CRUDController() {
		Class klass = this.getClass();
		if (klass.isAnnotationPresent(RequestMapping.class)) {
			RequestMapping rm = (RequestMapping) klass.getAnnotation(RequestMapping.class);
			controllerRequestMappingValue = rm.value()[0];// 默认取第一个值
		} else {
			throw new RuntimeException("Must declare @RequestMapping at controller:" + klass.getName());
		}

		String viewFolder = getViewFloder();
		this.form_view_page = viewFolder + "/form";
		this.object_view_page = viewFolder + "/view";
		this.list_view_page = viewFolder + "/list";
	}

	protected void logRequest(HttpServletRequest request) {
		if (request == null) {
			return;
		}
		ObjectMapper mapper = new ObjectMapper();
		try {
			log.info("uri={}, data=[{}] ,ip=[{}] ", new Object[] { request.getRequestURI(), mapper.writeValueAsString(request.getParameterMap()), request.getRemoteHost() });
		} catch (JsonProcessingException e) {
			log.error(e.getMessage(), e);
		}
	}

	protected void logResponse(HttpServletResponse response) {

	}

	/**
	 * 由子类提供对应的Service实例
	 * @return
	 */
	public abstract BaseService<T, ID> getService();

	/**
	 * 视图存放目录
	 * @return
	 */
	public String getViewFloder() {
		return ObjectUtil.lowerSimpleClassName(this.getClass());
	}

	/**
	 * 新增表单页面
	 * @return
	 */
	@RequestMapping(params = "form", method = RequestMethod.GET)
	public String createForm(@ModelAttribute("model") T model, HttpServletRequest request) {
		return form_view_page;
	}

	/**
	 * 跳转到修改表单的页面
	 * @return
	 */
	@RequestMapping(value = "update/{id}", method = RequestMethod.GET)
	public ModelAndView updateForm(@PathVariable("id") ID id, HttpServletRequest request) {
		logRequest(request);
		T model = getService().get(id);
		return new ModelAndView(form_view_page, "model", model);
	}

	/**
	 * 新增或修改实体
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(params = "add", method = RequestMethod.POST)
	public ModelAndView save(HttpServletRequest request, @ModelAttribute("model") @Valid T model, BindingResult result, RedirectAttributes redirect) {
		logRequest(request);
		if (result.hasErrors()) {
			return new ModelAndView(form_view_page, "", model);
		}
		model = createHook(request, model);
		String message = "数据添加完成!";
		ID id = getService().add(model);
		redirect.addFlashAttribute("message", message);
		return new ModelAndView("redirect:/" + controllerRequestMappingValue + "/{id}", "id", id);
	}

	@RequestMapping(params = "update", method = RequestMethod.POST)
	public ModelAndView update(HttpServletRequest request, @Valid T model, BindingResult result, RedirectAttributes redirect) {
		logRequest(request);
		if (result.hasErrors()) {
			return new ModelAndView(form_view_page, "", model);
		}
		model = updateHook(request, model);
		String message = "数据修改完成!";
		if (!getService().update(model)) {
			message = "修改记录失败!";
		}
		redirect.addFlashAttribute("message", message);
		//获取id
		Object id = new ModelTableInfo(model.getClass()).getIdKey().get(model);
		System.err.println("id:" + id);
		return new ModelAndView("redirect:/" + controllerRequestMappingValue + "/{id}", "id", id);

	}

	protected T updateHook(HttpServletRequest request, T model) {
		return model;
	}

	protected T createHook(HttpServletRequest request, T model) {
		return model;
	}

	/**
	 * 查看实体信息
	 * @return
	 */
	@RequestMapping(value = "{id}")
	public ModelAndView get(@PathVariable ID id, HttpServletRequest request) {
		logRequest(request);
		T bean = getService().get(id);
		// check null
		//logResponse(response);
		return new ModelAndView(object_view_page, "model", bean);
	}

	/**
	 * 列表页面,含分页
	 * @return
	 */
	//@RequestMapping("pageList")
	@RequestMapping
	public ModelAndView listPage(HttpServletRequest request, T model, Page<T> page) {
		logRequest(request);
		WebPageSearchCondition<T> searchCondition = new WebPageSearchCondition<T>(model, request.getParameterMap());
		page = getService().queryForPage(searchCondition, page);
		listHook(page.getItems());
		
		Map<String,Object> map = new HashMap<String,Object>(2);
		map.put("page", page);
		map.put("searchCondition", searchCondition);
		return new ModelAndView(list_view_page, map);
	}

	protected void listHook(List<T> items) {

	}

	@RequestMapping(value = "delete/{id}")
	public ModelAndView delete(@PathVariable("id") ID id, HttpServletRequest request) {
		logRequest(request);
		getService().delete(id);
		Page<T> page = getService().queryForPage(null, new Page<T>());
		return new ModelAndView(list_view_page, "page", page);
	}

}
